package com.zhijian.medical.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import com.zhijian.medical.dao.local.ExperimentProcessCsvMapper;
import com.zhijian.medical.entity.po.ExperimentProcessCsv;
import com.zhijian.medical.entity.po.ExperimentProcessSample;
import com.zhijian.medical.entity.vo.request.ExperimentProcessCsvSaveOrUpdateVo;
import com.zhijian.medical.entity.vo.request.ExperimentProcessCsvSearchVo;
import com.zhijian.medical.entity.vo.request.ExperimentProcessSampleSearchVo;
import com.zhijian.medical.entity.vo.response.ExperimentProcessCsvVo;
import com.zhijian.medical.entity.vo.response.ExperimentProcessSampleVo;
import com.zhijian.medical.service.ExperimentProcessCsvService;
import com.zhijian.medical.service.ExperimentProcessSampleService;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 实验流程-csv文件导入信息业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-04-08 16:03:02
 */
@Slf4j
@Service
public class ExperimentProcessCsvServiceImpl implements ExperimentProcessCsvService {

    @Autowired
    private ExperimentProcessCsvMapper mapper;

    @Autowired
    private ExperimentProcessSampleService experimentProcessSampleService;

    @Override
    public ExperimentProcessCsv selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public ExperimentProcessCsvVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Long insert(ExperimentProcessCsv experimentProcessCsv) {
        Date now = new Date();
        experimentProcessCsv.setCreateTime(now);
        experimentProcessCsv.setUpdateTime(now);
        return mapper.insert(experimentProcessCsv) > 0 ? experimentProcessCsv.getId() : 0L;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean insertOrUpdate(ExperimentProcessCsvSaveOrUpdateVo experimentProcessCsvSaveOrUpdateVo) {
        //上来直接删除
        this.deleteByExperimentProcessId(experimentProcessCsvSaveOrUpdateVo.getExperimentProcessId());
        experimentProcessCsvSaveOrUpdateVo.getExperimentProcessCsvList().forEach(experimentProcessCsv -> {
            experimentProcessCsv.setExperimentProcessId(experimentProcessCsvSaveOrUpdateVo.getExperimentProcessId());
            this.insert(experimentProcessCsv);
        });
        return true;
    }

    @Override
    public boolean update(ExperimentProcessCsv experimentProcessCsv) {
        Date now = new Date();
        experimentProcessCsv.setUpdateTime(now);
        return mapper.updateByPrimaryKey(experimentProcessCsv) != 0;
    }

    @Override
    public Integer count(ExperimentProcessCsvSearchVo experimentProcessCsvSearchVo) {
        return mapper.count(experimentProcessCsvSearchVo);
    }

    @Override
    public List<ExperimentProcessCsvVo> selectList(ExperimentProcessCsvSearchVo experimentProcessCsvSearchVo) {
        return mapper.selectList(experimentProcessCsvSearchVo);
    }

    @Override
    public Page<ExperimentProcessCsvVo> selectPage(ExperimentProcessCsvSearchVo experimentProcessCsvSearchVo) {
        //先直接查总数
        int count = count(experimentProcessCsvSearchVo);
        //分页
        Page<ExperimentProcessCsvVo> page = new Page<>(true, count, experimentProcessCsvSearchVo.getPageNum(), experimentProcessCsvSearchVo.getPageSize());
        experimentProcessCsvSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<ExperimentProcessCsvVo> responseVos = this.selectList(experimentProcessCsvSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public void deleteByExperimentProcessId(Long experimentProcessId) {
        mapper.deleteByExperimentProcessId(experimentProcessId);
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public List<ExperimentProcessCsvVo> importCsv(Long experimentProcessId, MultipartFile file) {
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        CsvReader csvReader = CsvUtil.getReader();
        assert inputStream != null;
        CsvData read = csvReader.read(new InputStreamReader(inputStream, Charset.forName("UTF_16LE")));
        List<CsvRow> rows = read.getRows();
        //每次上传都直接把上次的删掉，覆盖
        this.deleteByExperimentProcessId(experimentProcessId);

        for (int i = 1; i < rows.size(); i++) {
            List<String> rawList = rows.get(i).getRawList();
            if (CollectionUtils.isEmpty(rawList)) {
                continue;
            }
            String s = rawList.get(0);
            String[] split = s.split("\\t");
            if (split.length < 7) {
                continue;
            }
            String b = split[1];
            String c = split[2];
            String d = split[3];
            String e = split[4];
            if (StringUtils.isAllBlank(b, c, d, e)) {
                continue;
            }

            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectByFzblh(b);

            AssertUtil.check(Objects.isNull(experimentProcessSample) || Objects.isNull(experimentProcessSample.getExperimentProcessId()) || !Objects.equals(experimentProcessSample.getExperimentProcessId(), experimentProcessId), String.format("分子病理号为'%s'的样本，不存在于此次试验，请检查后重新导入", b));

            this.insert(ExperimentProcessCsv.builder()
                    .experimentProcessId(experimentProcessId)
                    .fzblh(b)
                    .cgblh(experimentProcessSample.getConventionPathologyNumber())
                    .nd(new BigDecimal(c))
                    .od260280(new BigDecimal(d))
                    .od260230(new BigDecimal(e))
                    .project(experimentProcessSample.getProject())
                    .build());
        }
        return this.selectList(ExperimentProcessCsvSearchVo.builder()
                .experimentProcessId(experimentProcessId)
                .build());
    }

    @Override
    public List<ExperimentProcessCsvVo> selectListByExperimentProcessId(Long experimentProcessId) {
        List<ExperimentProcessCsvVo> experimentProcessCsvVos = this.selectList(ExperimentProcessCsvSearchVo.builder()
                .experimentProcessId(experimentProcessId)
                .build());
        if (CollectionUtil.isNotEmpty(experimentProcessCsvVos)) {
            return experimentProcessCsvVos;
        }
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .experimentProcessId(experimentProcessId)
                .build());
        if (CollectionUtil.isEmpty(experimentProcessSampleVos)) {
            return Collections.emptyList();
        }
        return experimentProcessSampleVos.stream().map(e -> {
            ExperimentProcessCsvVo experimentProcessCsvVo = new ExperimentProcessCsvVo();
            experimentProcessCsvVo.setExperimentProcessId(experimentProcessId);
            experimentProcessCsvVo.setFzblh(e.getMoleculePathologyNumber());
            experimentProcessCsvVo.setCgblh(e.getConventionPathologyNumber());
            experimentProcessCsvVo.setNd(new BigDecimal(e.getNd()));
            experimentProcessCsvVo.setOd260280(e.getOd260280());
            experimentProcessCsvVo.setOd260230(e.getOd260230());
            experimentProcessCsvVo.setProject(e.getProject());
            experimentProcessCsvVo.setProjectName(e.getProject());
            return experimentProcessCsvVo;
        }).collect(Collectors.toList());
    }

}